#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
@Author:    Colin
@Github:    https://github.com/opscolin
@Gitee:     https://gitee.com/colin5063
@DateTime:  2022/9
@File:      config.py
@Software:  PyCharm
"""

import json

from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.auth.credentials import AccessKeyCredential
from aliyunsdkcore.auth.credentials import StsTokenCredential

# redis
from aliyunsdkr_kvstore.request.v20150101.DescribeSlowLogRecordsRequest import DescribeSlowLogRecordsRequest
from aliyunsdkr_kvstore.request.v20150101.DescribeInstancesRequest import DescribeInstancesRequest as DescribeRedisInstancesRequest
from aliyunsdkr_kvstore.request.v20150101.DescribeParametersRequest import DescribeParametersRequest
from aliyunsdkr_kvstore.request.v20150101.DescribeBackupsRequest import DescribeBackupsRequest

# rds
from aliyunsdkrds.request.v20140815.DescribeSlowLogRecordsRequest import DescribeSlowLogRecordsRequest
from aliyunsdkrds.request.v20140815.DescribeDBInstancesRequest import DescribeDBInstancesRequest
from aliyunsdkrds.request.v20140815.DescribeDBInstanceAttributeRequest import DescribeDBInstanceAttributeRequest
from aliyunsdkrds.request.v20140815.DescribeResourceUsageRequest import DescribeResourceUsageRequest

# ecs
# create 接口创建主机之后是停止状态，不启动
# from aliyunsdkecs.request.v20140526.CreateInstanceRequest import CreateInstanceRequest
from aliyunsdkecs.request.v20140526.RunInstancesRequest import RunInstancesRequest
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
# 添加重启的目的是为了解决自定义镜像主机名变更之后更新其他服务的配置文件，比如zabbix-agent.conf中的hostname
from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest

from aliyunsdkrds.request.v20140815.DescribeDBInstancePerformanceRequest import DescribeDBInstancePerformanceRequest
from aliyunsdkrds.request.v20140815.DescribeDBInstancesRequest import DescribeDBInstancesRequest


class AliyunAPI:
    def __init__(self, ak, sk, region_id='cn-beijing'):
        self.ak = ak
        self.sk = sk
        self.region_id = region_id
        self._credentials = AccessKeyCredential(self.ak, self.sk)
        self._client = AcsClient(region_id=self.region_id, credential=self._credentials)

    def common_request_api(self, request, *args, **kwargs):
        """阿里云查询接口公共api"""
        # print("arguments: args-> ", args)
        # print("arguments: kwargs-> ", kwargs)
        if kwargs:
            for k, v in kwargs.items():
                request.add_query_param(k, v)

        request.set_accept_format('json')
        response = json.loads(self._client.do_action_with_exception(request))

        # print(f"Debug: {response}")
        # 获取结果总数
        if 'TotalRecordCount' in response.keys():
            total_count = response['TotalRecordCount']
        elif 'TotalCount' in response.keys():
            total_count = response['TotalCount']
        else:
            total_count = 0

        # 获取最大页码
        if 'PageSize' in kwargs:
            page_max = int(total_count / kwargs['PageSize']) + 1
        else:
            page_max = int(total_count / 30) + 1

        # 兼容各类接口结果展示，最终只返回"需要的"结果部分
        if 'Items' in response.keys():
            api_type = 'Items'
            api_record = list(response['Items'].keys())[0]
        elif 'Instances' in response.keys():
            api_type = 'Instances'
            api_record = list(response['Instances'].keys())[0]
        elif 'RunningParameters' in response.keys():
            api_type = 'RunningParameters'
            api_record = list(response['RunningParameters'].keys())[0]
        elif 'Backups' in response.keys():
            api_type = 'Backups'
            api_record = list(response['Backups'].keys())[0]
        elif 'PerformanceKeys' in response.keys():
            api_type = 'PerformanceKeys'
            api_record = list(response['PerformanceKeys'].keys())[0]

        # print(f"Total count: {total_count}; Page Max: {page_max}; api_type: {api_type}; api_record: {api_record}")

        if page_max == 1:
            # print(f"Debug: {response[api_type][api_record]}")
            yield response[api_type][api_record]
        else:
            for page in range(1, page_max + 1):
                request.set_PageNumber(page)
                yield json.loads(self._client.do_action_with_exception(request))[api_type][api_record]

    # ------------------------ Redis ------------------------ #
    def redis_list(self):
        request = DescribeRedisInstancesRequest()
        params = {'PageSize': 100}
        result = self.request_api(request, params)
        return result

    # ------------------------ Redis ------------------------ #
    def rds_list(self):
        request = DescribeDBInstancesRequest()
        params = {'PageSize': 100}
        result = self.common_request_api(request, **params)
        return result

    def rds_detail(self, instance_id):
        """实例属性获取实例详情"""
        request = DescribeDBInstanceAttributeRequest()
        params = {'DBInstanceId': instance_id}
        result = self.common_request_api(request, **params)
        return result

    def rds_performance_metric(self, instance_id, metric_key):
        """获取rds的每分钟指定的监控数据"""
        request = DescribeDBInstancePerformanceRequest()
        start_time = (datetime.utcnow() - timedelta(minutes=2)).strftime('%Y-%m-%dT%H:%MZ')
        end_time = (datetime.utcnow() - timedelta(minutes=1)).strftime('%Y-%m-%dT%H:%MZ')
        params = {
            "DBInstanceId": instance_id,
            "Key": metric_key,
            "StartTime": start_time,
            "EndTime": end_time
        }
        result = self.common_request_api(request, **params)
        return result

    def rds_cpu_memory_metric(self, instance_id):
        """获取rds的CPU和Memory 每分钟的监控数据"""
        _res = next(self.rds_performance_metric(instance_id, 'MySQL_MemCpuUsage'))
        value = _res[0]['Values']['PerformanceValue'][0]['Value']
        _cpu, _memory = value.split('&')
        return _cpu, _memory

    def rds_iops_metric(self, instance_id):
        """获取RDS实例的 IOPS"""
        _res = next(self.rds_performance_metric(instance_id, 'MySQL_IOPS'))
        return _res[0]['Values']['PerformanceValue'][0]['Value']

    def rds_disk_size(self, instance_id):
        info = self.rds_detail(instance_id)
        # size = info[0]['DBInstanceStorage']
        size = next(info)[0]['DBInstanceStorage']
        return size

    def rds_disk_used_size(self, instance_id):
        request = DescribeResourceUsageRequest()
        request.set_accept_format('json')
        request.set_DBInstanceId(instance_id)
        response = json.loads(self._client.do_action_with_exception(request))
        return response['DiskUsed']

    # ------------------------ ECS ------------------------ #
    def ecs_list(self, zone_id=None):
        request = DescribeInstancesRequest()
        params = {'PageSize': 100}
        if zone_id:
            # 这里采用update之后，虽然params更新了，但是传递给request_id 之后貌似没有，why?
            params.update({'ZoneId': zone_id})
            # params['ZoneId'] = zone_id
        result = self.request_api(request, params)
        return result

    def ecs_detail(self, instance_name):
        request = DescribeInstancesRequest()
        params = {'InstanceName': instance_name}
        result = self.request_api(request, params)
        return result

    def ecs_status(self, ids):
        request = DescribeInstancesRequest()
        params = {'InstanceIds': ids}
        result = self.request_api(request, params)
        return result

    def ecs_reboot(self, id):
        request = RebootInstanceRequest()
        params = {'InstanceId': id}
        result = self.request_api_update(request, params)
        return result

    def ecs_create(self, hostname, instance_type, security_group, switch_id,
                   zone_id='cn-beijing-f', period_type=0,
                   system_disk=40, system_disk_category='cloud_efficiency',
                   data_disk=None
                   ):
        pass

    def ecs_exists(self, name):
        pass

    def ecs_status(self, status='running'):
        pass

    # ------------------------ Other  ------------------------ #
    @staticmethod
    def local_time_to_utctime(dt, str_format="%Y-%m-%dT%H:%MZ"):
        utc_time = dt + relativedelta(hours=-8)
        return utc_time.strftime(str_format)